package com.xbongbong.paas.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.message.domain.entity.PushSetEntity;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormEntity;
import com.xbongbong.paas.domain.entity.PaasMenuEntity;
import com.xbongbong.paas.domain.entity.ext.OptionalRangeEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.OptionalRangeEnum;
import com.xbongbong.paas.enums.StarEnum;
import com.xbongbong.paas.field.ItemPoJo;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.ProFormHelp;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.CrmLogMemoConstant;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.model.PaasMenuModel;
import com.xbongbong.paas.pojo.CustomerRulePojo;
import com.xbongbong.paas.pojo.CustomerRuleTypePojo;
import com.xbongbong.paas.pojo.CustomerUserPojo;
import com.xbongbong.paas.pojo.LeadOrFrePojo;
import com.xbongbong.paas.pojo.PublicRuleLabelPojo;
import com.xbongbong.paas.pojo.RestrictPojo;
import com.xbongbong.paas.pojo.RuleSavePojo;
import com.xbongbong.paas.pojo.dto.CustomerRuleDetailDTO;
import com.xbongbong.paas.pojo.dto.CustomerRuleGetRemindTimeDTO;
import com.xbongbong.paas.pojo.dto.CustomerRuleListDTO;
import com.xbongbong.paas.pojo.dto.CustomerRuleSaveDTO;
import com.xbongbong.paas.pojo.dto.CustomerRuleSaveRemindTimeDTO;
import com.xbongbong.paas.pojo.dto.CustomerRuleUserListDTO;
import com.xbongbong.paas.pojo.dto.ReturnCustomer2PublicAsyncDTO;
import com.xbongbong.paas.pojo.vo.CustomerListRuleVO;
import com.xbongbong.paas.pojo.vo.CustomerRuleDetailVO;
import com.xbongbong.paas.pojo.vo.CustomerRuleRemindTimeVO;
import com.xbongbong.paas.pojo.vo.CustomerRuleUserListVO;
import com.xbongbong.paas.pojo.vo.CustomerRuleVO;
import com.xbongbong.paas.pojo.vo.ReturnCustomer2PublicAsyncVO;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.service.CustomerRuleService;
import com.xbongbong.paas.service.TemplateService;
import com.xbongbong.paas.service.dynamic.help.DynamicDetailsHelper;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.XbbResponse;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.customercommunicate.pojo.dto.DynamicDTO;
import com.xbongbong.pro.domain.entity.LabelEntity;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.ErrorCodeEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.UpdateCustomerTeamScenesEnum;
import com.xbongbong.pro.enums.errorcodes.PublicPoolErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.UserTeamErrorCodeEnum;
import com.xbongbong.pro.message.constant.CustomerBackPushConstant;
import com.xbongbong.pro.message.enums.PushObjectTypeEnum;
import com.xbongbong.pro.message.enums.PushTypeEnum;
import com.xbongbong.pro.message.help.PushHelper;
import com.xbongbong.pro.message.model.PushSetModel;
import com.xbongbong.pro.message.pojo.PushRefTypePojo;
import com.xbongbong.pro.message.pojo.dto.MessageRabbitMqDTO;
import com.xbongbong.pro.message.pushset.CustomerPushSet;
import com.xbongbong.pro.message.service.MessageService;
import com.xbongbong.pro.template.pojo.EnablePojo;
import com.xbongbong.pro.template.pojo.dto.TemplateDTO;
import com.xbongbong.saas.constant.CustomerRuleConstant;
import com.xbongbong.saas.domain.entity.CustomerRuleEntity;
import com.xbongbong.saas.domain.entity.RuleCustomerEntity;
import com.xbongbong.saas.domain.entity.TagEntity;
import com.xbongbong.saas.domain.entity.TagLinkEntity;
import com.xbongbong.saas.domain.entity.ext.CustomerEntityExt;
import com.xbongbong.saas.enums.ChildCustomerRuleEnum;
import com.xbongbong.saas.enums.CompanyConfigEnum;
import com.xbongbong.saas.enums.CustomerChildTypeEnum;
import com.xbongbong.saas.enums.CustomerRuleEnum;
import com.xbongbong.saas.enums.CustomerSeniorRuleTypeEnum;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.ProjectLogEnum;
import com.xbongbong.saas.enums.TagTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.dictionary.DictionaryEnum;
import com.xbongbong.saas.enums.subform.CustomerTeamEnum;
import com.xbongbong.saas.factory.publicrule.CheckRuleFactory;
import com.xbongbong.saas.factory.publicrule.CheckRuleGainRate;
import com.xbongbong.saas.factory.publicrule.ICheckRule;
import com.xbongbong.saas.factory.publicrule.IOperateRuleValue;
import com.xbongbong.saas.factory.publicrule.OperateMaxCustomerNumRuleValue;
import com.xbongbong.saas.factory.publicrule.OperateRuleValueFactory;
import com.xbongbong.saas.help.PublicSeniorRuleHelp;
import com.xbongbong.saas.model.CustomerModel;
import com.xbongbong.saas.model.CustomerRuleModel;
import com.xbongbong.saas.model.CustomerUserModel;
import com.xbongbong.saas.model.DataDictionaryModel;
import com.xbongbong.saas.model.IndexTypeModel;
import com.xbongbong.saas.model.LabelModel;
import com.xbongbong.saas.model.TagLinkModel;
import com.xbongbong.saas.model.TagModel;
import com.xbongbong.saas.service.CustomerUserService;
import com.xbongbong.saas.service.UserTeamService;
import com.xbongbong.sys.domain.entity.CompanyConfigEntity;
import com.xbongbong.sys.domain.entity.CompanyEntity;
import com.xbongbong.sys.domain.entity.DepartmentEntity;
import com.xbongbong.sys.domain.entity.RoleEntity;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.help.SysEnvHelp;
import com.xbongbong.sys.model.CompanyConfigModel;
import com.xbongbong.sys.model.CompanyModel;
import com.xbongbong.sys.model.DepartmentModel;
import com.xbongbong.sys.model.RoleModel;
import com.xbongbong.sys.model.UserModel;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;

/**
 * @author youli.chen
 * @ProjectName xbb-pro
 * @Description: 公海池规则方法实现类
 * @date 2019/1/24 14:35
 */
@Service("customerRuleService")
public class CustomerRuleServiceImpl implements CustomerRuleService {

    private static final Logger LOG = LoggerFactory.getLogger(CustomerRuleServiceImpl.class);

    @Resource
    private CustomerRuleModel customerRuleModel;
    @Resource
    private UserModel userModel;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    private CompanyConfigModel companyConfigModel;
    @Resource
    private PushSetModel pushSetModel;
    @Resource
    private TagLinkModel tagLinkModel;
    @Resource
    private TagModel tagModel;
    @Resource
    private CustomerModel customerModel;
    @Resource
    private CheckRuleFactory checkRuleFactory;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private MessageService messageService;
    @Resource
    private CustomerUserModel customerUserModel;
    @Resource
    private CustomerUserService customerUserService;
    @Resource
    @Lazy
    private UserTeamService userTeamService;
    @Resource
    private DataDictionaryModel dataDictionaryModel;
    @Resource
    private CompanyModel companyModel;
    @Resource
    private DepartmentModel departmentModel;
    @Resource
    private RoleModel roleModel;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private LabelModel labelModel;
    @Resource
    @Lazy
    private TemplateService templateService;

    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private PaasMenuModel paasMenuModel;
    @Resource
    private PushHelper pushHelper;
    @Resource
    private IndexTypeModel indexTypeModel;
    @Resource
    private PublicSeniorRuleHelp publicSeniorRuleHelp;
    @Resource
    private CommonHelp commonHelp;

    @Resource
    private DynamicDetailsHelper dynamicDetailsHelper;
    @Resource
    private ProFormHelp proFormHelp;
    @Resource
    private SysEnvHelp sysEnvHelp;
    /**
     * 【web】规则列表
     *
     * @param customerRuleListDTO 获取规则入参
     * @return CustomerListRuleVO
     * @throws XbbException 业务异常
     * @version v1.0
     * @since v1.0
     */
    @Override
    public XbbResponse<CustomerListRuleVO> getCustomerRuleList(CustomerRuleListDTO customerRuleListDTO) throws XbbException {

        // TODO 公海池规则设置权限判断 卡特
        CustomerListRuleVO customerListRuleVO = new CustomerListRuleVO();
        Map<String, Object> param = new HashMap<>(4);
        param.put("corpid", customerRuleListDTO.getCorpid());
        param.put("del", DelEnum.NORMAL.getDel());
        param.put("start", 0);
        param.put("pageNum", 10);
        List<CustomerRuleEntity> ruleList = customerRuleModel.findEntitys(param);
        Map<Integer, CustomerRuleEntity> ruleMap = new HashMap<>(10);
        for (CustomerRuleEntity rule : ruleList) {
            ruleMap.put(rule.getRuleType(), rule);
        }

        List<CustomerRuleEnum> enumList = CustomerRuleEnum.getAllEnum();

        List<CustomerRuleVO> ruleVOList = new ArrayList<>();
        for (CustomerRuleEnum ruleEnum : enumList) {
            CustomerRuleVO customerRuleVO = new CustomerRuleVO();
            Integer ruleType = ruleEnum.getCode();
            String typeName = ruleEnum.getName();
            String tip = ruleEnum.getTip();
            Integer status = 0;
            CustomerRuleEntity rule = ruleMap.get(ruleType);
            if (rule != null) {
                status = rule.getStatus();
            }
            customerRuleVO.setTypeName(typeName);
            customerRuleVO.setTip(tip);
            customerRuleVO.setStatus(status);
            customerRuleVO.setRuleType(ruleType);

            ruleVOList.add(customerRuleVO);
        }
        customerListRuleVO.setCustomerRuleList(ruleVOList);
        TemplateDTO templateDTO = new TemplateDTO();
        BeanUtil.copyProperties(customerRuleListDTO, templateDTO);
        templateDTO.setSubBusinessType(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode());
        templateDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
        List<EnablePojo> saasTemplateList = templateService.getSaasTemplateList(templateDTO);
        customerListRuleVO.setFormList(saasTemplateList);
        return new XbbResponse<>(customerListRuleVO);
    }

    /**
     * 【web】规则详情
     *
     * @param customerRuleDetailDTO 获取规则详情入参
     * @return CustomerRuleDetailVO
     * @throws XbbException 业务异常
     * @version v1.0
     * @since v1.0
     */
    @Override
    public XbbResponse<CustomerRuleDetailVO> getCustomerRuleDetail(CustomerRuleDetailDTO customerRuleDetailDTO) throws XbbException {
        String corpid = customerRuleDetailDTO.getCorpid();
        Integer ruleType = customerRuleDetailDTO.getRuleType();
        // 数据字典项：获取客户状态
        Map<String, String> customerStatusMap = dataDictionaryModel.getDictionaryMap(DictionaryEnum.CUSTOMER_STATUS, corpid, null);

        CustomerRuleDetailVO ruleDetailVO;
        try {
            ruleDetailVO = detail(ruleType, corpid);
        } catch (XbbException e) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        ruleDetailVO.setImportantDegreeArray(getImportantDegree(false));
        ruleDetailVO.setImportantDegreeArraySort(getImportantDegree(true));
        ruleDetailVO.setChildTypeArray(getChildTypeList(ruleType));

        // 数据字典项：获取客户状态
        ruleDetailVO.setTypeArray(customerStatusMap);

        return new XbbResponse<>(ruleDetailVO);
    }

    /**
     * 【web】保存规则
     *
     * @param customerRuleSaveDTO 保存规则入参
     * @return Integer
     * @throws XbbException 业务异常
     * @version v1.0
     * @since v1.0
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public XbbResponse<Integer> save(CustomerRuleSaveDTO customerRuleSaveDTO) throws XbbException {
        // TODO 公海池规则设置权限判断 卡特
        String corpid = customerRuleSaveDTO.getCorpid();
        CustomerRuleEntity oldEntity = customerRuleModel.getByRuleType(customerRuleSaveDTO.getRuleType(), corpid);
        Integer customerRuleId = save(corpid, customerRuleSaveDTO);
        CustomerRuleEntity newEntity = customerRuleModel.getByRuleType(customerRuleSaveDTO.getRuleType(), corpid);
        try {
            saveLog(corpid, oldEntity, newEntity, customerRuleSaveDTO);
        } catch (Exception e) {
            LOG.error("日志保存错误");
        }
        return new XbbResponse<>(customerRuleId);
    }

    /**
     * 【web】保存公海池退回提醒时间
     *
     * @param customerRuleSaveRemindTimeDTO 保存公海池退回提醒时间入参
     * @return Integer
     * @throws XbbException 业务异常
     * @version v1.0
     * @since v1.0
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public XbbResponse<Integer> saveRemindTime(CustomerRuleSaveRemindTimeDTO customerRuleSaveRemindTimeDTO) throws XbbException {
        // TODO 公海池规则设置权限判断 卡特
        String corpid = customerRuleSaveRemindTimeDTO.getCorpid();
        String usedId = customerRuleSaveRemindTimeDTO.getUserId();
        // 登录用户
        String loginUserName = customerRuleSaveRemindTimeDTO.getLoginUserName();
        Integer saveRemindTimeId;
        try {
            saveRemindTimeId = saveRemindTime(corpid, customerRuleSaveRemindTimeDTO.getDay());
        } catch (XbbException e) {
            LOG.error("保存公海池客户退回提醒时间失败");
            throw new XbbException(PublicPoolErrorCodeEnum.API_ERROR_218002);
        }

        // 日志
        CompanyConfigEntity companyConfig = companyConfigModel.initConfigEntity(corpid, CompanyConfigEnum.PUBLIC_RULE_REMIND_TIME.getAlias());
        //TODO 后面和卡特再商量一下这个类型枚举
        String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_SET_BACK_TIME_CUSTOMER_RULE), companyConfig.getConfigName(), companyConfig.getConfigValue());
        mongoLogHelp.buildLog(corpid, usedId, loginUserName, OperateModuleTypeEnum.OpenSeaRules, OperateTypeEnum.SET, companyConfig.getId().toString(), companyConfig.getConfigName(), memo, customerRuleSaveRemindTimeDTO.getHttpHeader());
        return new XbbResponse<>(saveRemindTimeId);
    }

    /**
     * 【web】获取公海池退回提醒时间
     *
     * @param customerRuleGetRemindTimeDTO 获取公海池退回提醒时间入参
     * @return Integer
     * @throws XbbException 业务异常
     * @version v1.0
     * @since v1.0
     */
    @Override
    public XbbResponse<CustomerRuleRemindTimeVO> getRemindTime(CustomerRuleGetRemindTimeDTO customerRuleGetRemindTimeDTO) throws XbbException {
        // TODO 公海池规则设置权限判断 卡特
        String corpid = customerRuleGetRemindTimeDTO.getCorpid();
        Integer remindTime = Integer.valueOf(CompanyConfigEnum.PUBLIC_RULE_REMIND_TIME.getValue());
        try {
            CompanyConfigEntity companyConfig = companyConfigModel.initConfigEntity(corpid,
                    CompanyConfigEnum.PUBLIC_RULE_REMIND_TIME.getAlias());
            if (companyConfig != null) {
                remindTime = StringUtil.toInt(companyConfig.getConfigValue(), remindTime);
            }
        } catch (Exception e) {
            LOG.error("getRemindTime异常，corpid=" + corpid, e);
            throw new XbbException(PublicPoolErrorCodeEnum.API_ERROR_218003);
        }
        CustomerRuleRemindTimeVO customerRuleRemindTimeVO = new CustomerRuleRemindTimeVO();
        customerRuleRemindTimeVO.setBackDay(remindTime);
        return new XbbResponse<>(customerRuleRemindTimeVO);
    }

    /**
     * 单公司跟进公海规则退回公海
     * @param corpid 公司id
     * @param back false不需要退回公海池   true退回公海池
     * @param notify false不需要即将退回提醒   true即将退回提醒
     * 创建时间 2019/2/27 4:25 PM
     * 修改时间 2019/2/27 4:25 PM
     * @author chy
     * @since v1.0
     * @version v1.0
     */
    private void backToPublic(String corpid, boolean notify, boolean back) {
        LOG.info("returnCustomer_start: " + corpid);
        try {

            //推送规则，此处规则现在只有是否推送给主负责人
            boolean isPushMain = getIsPushMain(corpid);

            // 开启推送，将更新标签（删除该公司的所有退回公海池标签）
            if (notify) {
                tagLinkModel.deleteReturnPublicTags(corpid, TagTypeEnum.PUBLIC_CUSTOMER_RULE.getCode());
            }


            //获取公司所有的相关公海规则   无新建跟进客户规则  无新建机会客户规则  无新建合同客户规则 最大拥有客户数规则
            List<CustomerRuleEntity> ruleList = getRuleRelatedScript(corpid);

            //获取提醒时间配置
            Integer advanceTime = getRemindTime(corpid);

            // 获取menuId，用来移除经销商数据
            PaasMenuEntity paasMenuEntity = paasMenuModel.getByAlias4Distributor(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getAlias(), corpid, DistributorMarkEnum.OTHER.getCode());

            Map<String, Object> userParam = new HashMap<>(5);
            userParam.put("corpid", corpid);
            //若是将异常的del状态的一起跑，会有很多user被跑到（前三家是近四万---近九万）
            userParam.put("del", 0);
            //一页200
            Integer pagerNum = 200;
            // 当前公司的用户总数
            Integer userCount = userModel.getEntitysCount(userParam);
            //总页数
            Integer pageTotal = userCount / pagerNum;
            //不能整除，页码加1
            if (userCount % pagerNum > 0) {
                ++pageTotal;
            }
            for (int page = 0; page < pageTotal; page++) {
                Integer start = page * pagerNum;
                userParam.put("start", start);
                userParam.put("pageNum", pagerNum);
                userParam.put("columns", "corpid,user_id,name,role_ids,department");
                List<UserEntity> users = userModel.findEntitys(userParam);
                for (UserEntity user : users) {

                    //当前员工负责客户数大于1万跳过处理
                    Integer count = mainCount(corpid, user.getUserId());
                    if (count > 10000) {
                        LOG.error("coount > 10000,corpid:" + corpid + "userId:" + user.getUserId());
                        continue;
                    }

                    for (CustomerRuleEntity rule : ruleList) {
                        //执行完一条规则，员工拥有的客户可能会发生变化
                        Integer ruleType = rule.getRuleType();
                        //最大客户数逻辑不能用分页处理区分处理
                        if (!Objects.equals(ruleType, CustomerRuleEnum.MAX_CUSTOMER_NUM_RULE.getCode())) {
                            backToPublic4NotMaxCount(corpid, user, back, notify, rule, advanceTime, isPushMain, paasMenuEntity.getId());
                        } else {
                            //最大客户数规则没有好的方案 还是以原来的方案处理
                            backToPublic4MaxCount(corpid, user, back, notify, rule, advanceTime, isPushMain, paasMenuEntity.getId());
                        }

                    }
                }
            }
            //一个公司操作完成，移除已打标签客户缓存
            paasRedisHelper.removeValue(RedisPrefixConstant.TAG_LINK_CUSTOMER_ID, corpid);
            try {
            } catch (Exception e) {
                LOG.error("搜索引擎更新客户\"即将退回公海池\"标签索引出错！公司Id：" + corpid);
            }
        } catch (Exception e) {
            LOG.error("backToPublic中出现了奇怪的异常, corpid:" + corpid, e);
        }
    }


    /**
     * 非最大客户数退回公海池（员工逻辑）
     * @param corpid
     * @param user
     * @param back
     * @param notify
     * @param rule
     * @param advanceTime
     * @param isPushMain
     */
    private void backToPublic4NotMaxCount(String corpid, UserEntity user, boolean back, boolean notify,
                             CustomerRuleEntity rule, Integer advanceTime, boolean isPushMain, Long menuId){

        Integer ruleType = rule.getRuleType();
        ICheckRule checkRule = null;
        try {
            checkRule = checkRuleFactory.checkRuleFactory(ruleType);
        } catch (XbbException e) {
            LOG.error("corpid:" + corpid, e);
            return ;
        }

        //执行完一条规则，员工拥有的客户可能会发生变化，不能用page的分页
        Long startId = 0L;
        Integer pageNum = 1000;
        Long startTime = DateTimeUtil.getInt();
        List<Long> idIn = customerUserModel.getDataIdList4Rule(corpid, 1, user.getUserId(), startId, pageNum);
        String paramStr = "corpid:" + corpid + "isMain:" + 1 + "user.getUserId():" + user.getUserId() + "startId:" + startId + "pageNum:" + pageNum;
        while (idIn.size() > 0){
            List<RuleCustomerEntity> customerList = null;
            try {
                startTime = DateTimeUtil.getInt();
                customerList = customerModel.getMainCustomerList4Rule(corpid, idIn, menuId);
                paramStr = "corpid:" + corpid + " idIn.size:" + idIn.size() + "menuId:" + menuId;
            } catch (Exception e) {
                LOG.error("customerModel.getMainCustomerList4Rule error corpid:" + corpid + " idIn:" + idIn);
            }

            List<RuleCustomerEntity> backCustomerList = null;
            if(back){
                try {
                    backCustomerList = checkRule.getBackCustomerList(user, rule, customerList);
                } catch (XbbException e) {
                    LOG.error("corpid:" + corpid + "ruleType:" + ruleType, e);
                    continue;
                }
                if (backCustomerList != null && backCustomerList.size() > 0) {
                    return2Public(user, backCustomerList, rule.getRuleType());
                    pushReturnMessage(user, backCustomerList, rule.getRuleType());
                }
            }
            if(notify){
                List<RuleCustomerEntity> notifyCustomerList = null;
                remove(customerList, backCustomerList);
                try {
                    notifyCustomerList = checkRule.getBackCustomerList(user, rule, customerList, advanceTime);
                } catch (XbbException e) {
                    LOG.error("XbbParamException_corpid:" + corpid + "ruleType:" + rule.getRuleType(), e);
                    continue;
                } catch (Exception e1) {
                    LOG.error("Exception_corpid:" + corpid + "ruleType:" + rule.getRuleType(), e1);
                    continue;
                }
                if (notifyCustomerList != null && notifyCustomerList.size() > 0) {
                    tagReturnPublic(user, notifyCustomerList);
                    if (isPushMain) {
                        pushTagMessage(user, notifyCustomerList, advanceTime);
                    }
                }
            }
            //最后的一个id作为起始id
            startId = idIn.get(idIn.size() - 1);
            idIn = customerUserModel.getDataIdList4Rule(corpid, 1, user.getUserId(), startId, pageNum);
        }
    }

    /**
     * 最大客户数退回公海池（员工逻辑）
     * @param corpid
     * @param user
     * @param back
     * @param notify
     * @param rule
     * @param advanceTime
     * @param isPushMain
     */
    private void backToPublic4MaxCount(String corpid, UserEntity user, boolean back, boolean notify,
                                          CustomerRuleEntity rule, Integer advanceTime, boolean isPushMain, Long menuId) throws XbbException {
        List<RuleCustomerEntity> customerList = customerModel.getMainCustomerListByUserId(corpid, user.getUserId(), null, null, null, null, null, null, menuId);
        Integer ruleType = rule.getRuleType();
        ICheckRule checkRule = null;
        try {
            checkRule = checkRuleFactory.checkRuleFactory(ruleType);
        } catch (XbbException e) {
            LOG.error("corpid:" + corpid, e);
            return ;
        }
        List<RuleCustomerEntity> backCustomerList = null;
        if(back){
            try {
                backCustomerList = checkRule.getBackCustomerList(user, rule, customerList);
            } catch (XbbException e) {
                LOG.error("corpid:" + corpid + "ruleType:" + ruleType, e);
                return ;
            }
            if (backCustomerList != null && backCustomerList.size() > 0) {
                return2Public(user, backCustomerList, rule.getRuleType());
                pushReturnMessage(user, backCustomerList, rule.getRuleType());
            }
        }

        if(notify){
            List<RuleCustomerEntity> notifyCustomerList = null;
            remove(customerList, backCustomerList);
            try {
                notifyCustomerList = checkRule.getBackCustomerList(user, rule, customerList, advanceTime);
            } catch (XbbException e) {
                LOG.error("XbbParamException_corpid:" + corpid + "ruleType:" + rule.getRuleType(), e);
                return ;
            } catch (Exception e1) {
                LOG.error("Exception_corpid:" + corpid + "ruleType:" + rule.getRuleType(), e1);
                return ;
            }
            if (notifyCustomerList != null && notifyCustomerList.size() > 0) {
                tagReturnPublic(user, notifyCustomerList);
                if (isPushMain) {
                    pushTagMessage(user, notifyCustomerList, advanceTime);
                }
            }
        }
    }


    @Override
    public Integer canGainCustomer(String corpid, UserEntity userEntity, Long customerId, List<CustomerRuleEntity> ruleList, int dataIdSize) throws XbbException {
        for (CustomerRuleEntity rule : ruleList) {
            ICheckRule checkRule = checkRuleFactory.checkRuleFactory(rule.getRuleType());
            boolean flag = checkRule.canGainCustomer(rule, corpid, userEntity, customerId, dataIdSize, null);
            //只要有一个规则不允许获取客户就不允许
            if (!flag) {
                return rule.getRuleType();
            }
        }
        return 0;
    }

    @Override
    public void updateGainRateToRedis(String corpid,
                                      UserEntity userEntity) throws XbbException{
        String userId = userEntity.getUserId();
        //获取用户的每天的捞取、分配频次
        Integer num = StringUtil.toInt(paasRedisHelper.getValue(RedisPrefixConstant.CUSTOMER_GAIN_RATE, corpid + "_" + userId), null);
        if(num == null){
            try {
                CustomerRuleEntity rule = null;
                //兼容老逻辑
                if (commonHelp.isCustomerPublicPoolSeniorModel(corpid)){
                    rule = publicSeniorRuleHelp.getCustomerRule(corpid, CustomerSeniorRuleTypeEnum.GAIN_RATE_RULE.getCode(),
                            XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode());
                }else {
                    rule = customerRuleModel.getByRuleType(CustomerRuleEnum.GAIN_RATE_RULE.getCode(), corpid);
                }
                if (Objects.isNull(rule)){
                    return;
                }
                ICheckRule checkRule = checkRuleFactory.checkRuleFactory(rule.getRuleType());
                CheckRuleGainRate checkRuleGainRate = (CheckRuleGainRate)checkRule;
                num = checkRuleGainRate.getCustomerGainRateFromDB(rule, userEntity);
            } catch (XbbException e) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
            }
        }
        if(num != null){
            num --;
            Long endTime = DateTimeUtil.getTodayInt()+86400L;
            Long now = DateTimeUtil.getInt();
            Long time = endTime - now;
            paasRedisHelper.setValue(RedisPrefixConstant.CUSTOMER_GAIN_RATE, corpid + "_" + userId, num, time.intValue());
        }
    }

    @Override
    public void updateGainRateByIds(String corpid,
                                      UserEntity userEntity, List<Long> ids) throws XbbException{
        //兼容老逻辑
        CustomerRuleEntity rule = null;
        if (commonHelp.isCustomerPublicPoolSeniorModel(corpid)){
            rule = publicSeniorRuleHelp.getCustomerRule(corpid, CustomerSeniorRuleTypeEnum.GAIN_RATE_RULE.getCode(),
                    XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode());
        }else {
            rule = customerRuleModel.getByRuleType(CustomerRuleEnum.GAIN_RATE_RULE.getCode(), corpid);
        }
        String userId = userEntity.getUserId();
        //获取用户的每天的捞取、分配频次
        Integer num = StringUtil.toInt(paasRedisHelper.getValue(RedisPrefixConstant.CUSTOMER_GAIN_RATE, corpid + "_" + userId), null);
        if(num == null){
            try {
                if (Objects.isNull(rule)){
                    return;
                }
                ICheckRule checkRule = checkRuleFactory.checkRuleFactory(rule.getRuleType());
                CheckRuleGainRate checkRuleGainRate = (CheckRuleGainRate)checkRule;
                num = checkRuleGainRate.getCustomerGainRateFromDB(rule, userEntity);
            } catch (XbbException e) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
            }
        }
        if(num != null){
            Integer idSize = ids.size();
            num -= idSize;
            Long endTime = DateTimeUtil.getTodayInt()+86400L;
            Long now = DateTimeUtil.getInt();
            Long time = endTime - now;
            paasRedisHelper.setValue(RedisPrefixConstant.CUSTOMER_GAIN_RATE, corpid + "_" + userId, num, time.intValue());
        }
    }

    @Async(value = "deletePublicTagThreadPool")
    @Override
    public void deletePublicTag(String corpid, List<Long> customerIds) throws XbbException {
        try {
            // TODO: 2022/9/19 改成队列延时
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            LOG.error("Thread.sleep", e);
            // 恢复中断状态
            Thread.currentThread().interrupt();
        }

        try {
            List<RuleCustomerEntity> customerList = formatRuleCustomer(customerModel.getByKeys(customerIds, corpid));
            List<UserEntity> userList = customerUserService.getMainUserList(customerIds, corpid, 1);
            //获取公司所有的相关公海规则   无新建跟进客户规则  无新建机会客户规则  无新建合同客户规则
            List<Integer> ruleTypeIn =  new ArrayList<>();
            ruleTypeIn.add(CustomerRuleEnum.NO_CUSTOMER_COMMUNICATE_RULE.getCode());
            ruleTypeIn.add(CustomerRuleEnum.NO_OPPORTUNITY_RULE.getCode());
            ruleTypeIn.add(CustomerRuleEnum.NO_CONTRACT_RULE.getCode());
            //数据库查询，获取影响到获取客户判断的三个规则
            Map<String, Object> param = new HashMap<>(3);
            param.put("corpid", corpid);
            param.put("ruleTypeIn", ruleTypeIn);
            param.put("del", 0);
            List<CustomerRuleEntity> ruleList = customerRuleModel.findEntitys(param);

            Integer advanceTime = getRemindTime(corpid);

            //此处不占位，下面checkRule.getBackCustomerList中返回少时，会少删除标签
            Map<Long, String> customerIdMemoMap = initCustomerIdMemoMap(customerIds);
            for(UserEntity user : userList){
                for(CustomerRuleEntity rule : ruleList){
                    ICheckRule checkRule = checkRuleFactory.checkRuleFactory(rule.getRuleType());

                    List<RuleCustomerEntity> notifyCustomerList = checkRule.getBackCustomerList(user, rule, customerList, advanceTime);

                    if(notifyCustomerList == null || notifyCustomerList.isEmpty()){
                        continue;
                    }
                    for (RuleCustomerEntity customerEntityExt : notifyCustomerList) {
                        String memo = customerIdMemoMap.get(customerEntityExt.getId());
                        if (StringUtil.isEmpty(memo)) {
                            memo = "";
                        }

                        if(StringUtil.isEmpty(memo)){
                            memo = customerEntityExt.getNotifyMemo();
                        }else{
                            memo += "," + customerEntityExt.getNotifyMemo();
                        }
                        customerIdMemoMap.put(customerEntityExt.getId(), memo);
                    }
                }
            }

            Set<Long> customerIdSet = customerIdMemoMap.keySet();
            for (Long customerId : customerIdSet) {
                String memo = customerIdMemoMap.get(customerId);
                updateTagLink(corpid, customerId, memo);
            }
        } catch (Exception e) {
            LOG.error("deletePublicTag error", e);
        }
    }

    private Map<Long, String> initCustomerIdMemoMap(List<Long> customerIds) {
        Map<Long, String> customerIdMemoMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (Long customerId : customerIds) {
            customerIdMemoMap.put(customerId, "");
        }
        return customerIdMemoMap;
    }

    private List<RuleCustomerEntity> formatRuleCustomer(List<CustomerEntityExt> CustomerEntityExts) {

        if (CustomerEntityExts == null) {
            return null;
        }

        List<RuleCustomerEntity> customers = new ArrayList<>();
        for (CustomerEntityExt customerEntityExt : CustomerEntityExts) {
            RuleCustomerEntity ruleCustomer = new RuleCustomerEntity();

            Long id = customerEntityExt.getId();
            Long appId = customerEntityExt.getAppId();
            Long menuId = customerEntityExt.getMenuId();
            String corpid = customerEntityExt.getCorpid();

            JSONObject json = JsonHelperUtil.getJSONObject(customerEntityExt.getData());
            String name = json.getString(CustomerManagementEnum.NAME.getAttr());
            Long lastConnectTime = json.getLong(CustomerManagementEnum.LAST_CONNECT_TIME.getAttr());
            Integer type = json.getInteger(CustomerManagementEnum.TYPE.getAttr());
            Integer importantDegree = json.getInteger(CustomerManagementEnum.IMPORTANT_DEGREE.getAttr());
            JSONArray jsonArray = json.getJSONArray(CustomerManagementEnum.LABEL.getAttr());
            List<Long> labels = null;
            if (CollectionsUtil.isNotEmpty(jsonArray)) {
                labels = JSON.parseArray(jsonArray.toJSONString(), Long.class);
            }
            if (Objects.isNull(labels)) {
                labels = new ArrayList<>();
            }
            ruleCustomer.setId(id);
            ruleCustomer.setAppId(appId);
            ruleCustomer.setMenuId(menuId);
            ruleCustomer.setCorpid(corpid);
            ruleCustomer.setName(name);
            ruleCustomer.setLastConnectTime(lastConnectTime);
            ruleCustomer.setType(type);
            ruleCustomer.setImportantDegree(importantDegree);
            ruleCustomer.setLabels(labels.toString());
            customers.add(ruleCustomer);
        }
        return customers;
    }

    /**
     * @Description: 更新标签
     * @param corpid 公司id
     * @param customerId 客户id
     * @param memo 标签备注
     * 创建时间： 2018-6-1 上午11:10:40
     * 修改时间： 2018-6-1 上午11:10:40 chy
     * @author chy
     * @since v3.22
     * @version v3.22
     */
    private void updateTagLink(String corpid, Long customerId, String memo) throws XbbException {
        TagLinkEntity tagLink = tagLinkModel.getTagByTagType(corpid, TagTypeEnum.PUBLIC_CUSTOMER_RULE.getCode(), customerId);
        TagEntity returnPublicTag = tagModel.findReturnPublicTag(TagTypeEnum.PUBLIC_CUSTOMER_RULE.getCode());

        if(StringUtil.isEmpty(memo)){
            if (tagLink == null){
                return ;
            }
            List<Long> refIdIn = new ArrayList<>();
            refIdIn.add(customerId);
            //该客户的所有主负责人都不需要退回公海提醒,删除客户标签
            tagLinkModel.deleteTagByTagTypeAndRefIdIn(corpid, TagTypeEnum.PUBLIC_CUSTOMER_RULE.getCode(), refIdIn);
        }else {
            if (memo.indexOf(I18nMessageUtil.getMessage(I18nStringConstant.WILL_RETURN_CUSTOMER_PUBLIC_N)) > -1) {
                memo = memo.replaceFirst(I18nMessageUtil.getMessage(I18nStringConstant.WILL_RETURN_CUSTOMER_PUBLIC_N), I18nMessageUtil.getMessage(I18nStringConstant.WILL_RETURN_CUSTOMER_PUBLIC_1));
            }
            if(tagLink == null){
                tagLink = new TagLinkEntity(corpid, "", returnPublicTag, customerId, XbbRefTypeEnum.CUSTOMER, memo);
            }else{
                tagLink.setMemo(memo);
            }
            tagLinkModel.save(tagLink);
        }
    }

    /**
     * 给用户发送即将退回公海的标签的提醒信息
     *
     * @param user         用户对象
     * @param customerList 符合提醒规则的客户列表
     * @author 章华隽
     * 创建时间： 2017/8/17 下午16:14
     * 修改时间：
     * @version
     * @since 3.11
     */
    private void pushTagMessage(UserEntity user, List<RuleCustomerEntity> customerList, Integer advanceTime) {
        String title = I18nMessageUtil.getMessage(CustomerBackPushConstant.CUSTOMER_WILL_BACK_TITLE);
        Map<Long, List<RuleCustomerEntity>> leftDayMap = customerList.stream().collect(Collectors.groupingBy(RuleCustomerEntity::getLeftDay));
        for(Map.Entry<Long,List<RuleCustomerEntity>> entry : leftDayMap.entrySet()){
            String content;
            List<RuleCustomerEntity> valueList = entry.getValue();
            String customerName = valueList.get(0).getName();
            if (valueList.size() > 1){
                content = String.format(I18nMessageUtil.getMessage(CustomerBackPushConstant.CUSTOMER_WILL_BACK_MORE), customerName, entry.getValue().size(), entry.getKey());
            }else {
                content = String.format(I18nMessageUtil.getMessage(CustomerBackPushConstant.CUSTOMER_WILL_BACK), customerName, entry.getKey());
            }
            pushMessage(user, valueList, title, content, PushTypeEnum.CUSTOMER_WILL_BACK_PUSH, XbbRefTypeEnum.CUSTOMER);
        }
    }

    /**
     * 为即将退回公海池的客户打上标签
     *
     * @param notifyCustomerList 即将退回公海池的客户列表
     */
    private void tagReturnPublic(UserEntity user, List<RuleCustomerEntity> notifyCustomerList) {

        String userId = user.getUserId();
        String corpid = user.getCorpid();

        TagEntity returnPublicTag = tagModel.findReturnPublicTag(TagTypeEnum.PUBLIC_CUSTOMER_RULE.getCode());

        if (notifyCustomerList == null || notifyCustomerList.isEmpty() || returnPublicTag == null) {
            return ;
        }

        Map<Long, TagLinkEntity> customerIdTagLinkMap = getCustomerIdTagLinkMap(corpid, userId, notifyCustomerList);
        ArrayList<TagLinkEntity> updateTagLinkList = new ArrayList<>();
        ArrayList<TagLinkEntity> insertTagLinkList = new ArrayList<>();
        for (RuleCustomerEntity customer : notifyCustomerList) {
            String memo = customer.getNotifyMemo();
            Long customerId = customer.getId();
            TagLinkEntity tagLink = null;

            if(customerIdTagLinkMap.containsKey(customerId)){
                tagLink = customerIdTagLinkMap.get(customerId);
                tagLink.setMemo(tagLink.getMemo() + "，" + memo);
                updateTagLinkList.add(tagLink);
            }else{
                tagLink = new TagLinkEntity(corpid, "", returnPublicTag, customerId, XbbRefTypeEnum.CUSTOMER_MANAGEMENT, memo);
                insertTagLinkList.add(tagLink);
            }

        }
        if(insertTagLinkList != null && insertTagLinkList.size() != 0){
            tagLinkModel.batchInsert(insertTagLinkList);
        }
        if(updateTagLinkList != null && updateTagLinkList.size() != 0){
            tagLinkModel.batchUpdate(updateTagLinkList);
        }
    }

    /**
     * 获取客户列表notifyCustomerList中，有tagLink的的map
     *
     * @param corpid
     * @param userId
     * @param notifyCustomerList 需要提醒的客户列表
     * @return 创建时间： 2018-5-29 下午4:51:57
     * 修改时间： 2018-5-29 下午4:51:57 chy
     * @author chy
     * @version v3.22
     * @since v3.22
     */
    private Map<Long, TagLinkEntity> getCustomerIdTagLinkMap(
            String corpid, String userId,
            List<RuleCustomerEntity> notifyCustomerList) {
        Set<Long> allCustomerId = new HashSet<>();

        Set<Long> tagLinkCustomerIdSet = new HashSet<>(16);
        Set<Integer> tagLinkCustomerIdRedis = null;
        try {
            //这边会被转化成Integer
            tagLinkCustomerIdRedis = paasRedisHelper.getValue4Set(RedisPrefixConstant.TAG_LINK_CUSTOMER_ID, corpid);
        } catch (Exception e) {
            // ignore
        }
        if(tagLinkCustomerIdRedis != null){
            for (Integer customerId : tagLinkCustomerIdRedis) {
                tagLinkCustomerIdSet.add(customerId.longValue());
            }
        }

        Map<Long, TagLinkEntity> retMap = new HashMap<>(16);

        Set<Long> customerIdSet = new HashSet<>();
        for (RuleCustomerEntity customer : notifyCustomerList) {
            customerIdSet.add(customer.getId());
        }
        allCustomerId.addAll(tagLinkCustomerIdSet);
        allCustomerId.addAll(customerIdSet);

        //取交集
        customerIdSet.retainAll(tagLinkCustomerIdSet);
        List<Long> customerIdIn = new ArrayList<>(customerIdSet);
        if (customerIdIn.size() != 0) {
            List<TagLinkEntity> list = tagLinkModel.getCompanyTagLinksByRefType(corpid, XbbRefTypeEnum.CUSTOMER_PUBLIC.getCode(), customerIdIn);
            for(TagLinkEntity tagLink : list){
                retMap.put(tagLink.getRefId(), tagLink);
            }
        }

        paasRedisHelper.setValue4Set(RedisPrefixConstant.TAG_LINK_CUSTOMER_ID, corpid, allCustomerId, 2 * 3600);
        return retMap;
    }

    /**
     * 给用户发送退回公海的提醒信息
     *
     * @param user         用户对象
     * @param customerList 符合退回规则的客户列表
     * @author 章华隽
     * 创建时间： 2017/8/17 下午16:14
     * 修改时间：
     * @version
     * @since 3.11
     */
    private void pushReturnMessage(UserEntity user, List<RuleCustomerEntity> customerList, Integer ruleType) {

//        JSONObject json = JsonHelperUtil.getJSONObject(customerList.get(0).getData());
//        String name = json.getString(CustomerManagementEnum.NAME.getAttr());
        String name = customerList.get(0).getName();

        CustomerRuleEnum customerRuleEnum = CustomerRuleEnum.getByCode(ruleType);
        String ruleName = customerRuleEnum.getName();
        String title = I18nMessageUtil.getMessage(CustomerBackPushConstant.CUSTOMER_BACK_TITLE);
        String content = "";
        if (customerList.size() > 1) {
            content = String.format(I18nMessageUtil.getMessage(CustomerBackPushConstant.CUSTOMER_BACK_MORE), name, customerList.size(), ruleName);
        } else {
            content = String.format(I18nMessageUtil.getMessage(CustomerBackPushConstant.CUSTOMER_BACK), name, ruleName);
        }

        pushMessage(user, customerList, title, content,
                PushTypeEnum.CUSTOMER_BACK_PUSH, XbbRefTypeEnum.CUSTOMER_PUBLIC);
    }

    /**
     * 给用户发送即将退回公海的提醒信息
     *
     * @param user         用户对象
     * @param customerList 符合提醒规则的客户列表
     * @author 章华隽
     * 创建时间： 2017/8/9 上午10:34
     * 修改时间： 2017/8/17 下午16:14 by 章华隽
     * @version
     * @since 3.11
     */
    private void pushMessage(UserEntity user, List<RuleCustomerEntity> customerList, String title,
                             String content, PushTypeEnum pushTypeEnum, XbbRefTypeEnum xbbRefTypeEnum) {

        if (customerList == null || customerList.isEmpty()) {
            return ;
        }

        RuleCustomerEntity customer = customerList.get(0);

        Long appId = customer.getAppId();
        Long menuId = customer.getMenuId();

        try {
            String corpid = user.getCorpid();
            List<String> userIds = Arrays.asList(user.getUserId());
            List<Long> refIds = new ArrayList<>();
            for (RuleCustomerEntity entity : customerList) {
                refIds.add(entity.getId());
            }
            Integer remind = 0;
            Long pushTime = DateTimeUtil.getTodayInt() + 32400;
            CustomerEntityExt customerEntity = new CustomerEntityExt();
            List<String> pushUserList = pushHelper.getUserIdListByPushSetRule(corpid, PushTypeEnum.CUSTOMER_BACK_PUBLIC.getCode(), PushTypeEnum.CUSTOMER_BACK_PUBLIC.getSubCode(), user, customerEntity);
            pushUserList.addAll(userIds);
            PushRefTypePojo.Options options = new PushRefTypePojo.Options(appId, menuId, refIds, SaasMarkEnum.SAAS.getCode(), xbbRefTypeEnum.getCode());
            MessageRabbitMqDTO messageRabbitMqDTO = new MessageRabbitMqDTO(corpid, pushUserList, refIds, remind,
                    pushTime, title, content, null, options);
            messageService.insertPushData(messageRabbitMqDTO, pushTypeEnum);
        } catch (Exception e) {
            LOG.error("消息入库失败", e);
        }
    }

    private void return2Public(UserEntity user, List<RuleCustomerEntity> customerList, Integer ruleType) {
        CustomerRuleEnum customerRuleEnum = CustomerRuleEnum.getByCode(ruleType);
        String ruleName = customerRuleEnum.getName();

        String corpid = user.getCorpid();
        String userName = user.getName();
        Map<String, Object> param;
        List<Long> customerIdList = new ArrayList<>();
        List<DynamicDTO> dynamicDTOS = new ArrayList<>(customerList.size());

        Map<Long, String> formIdToPaasNameMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        try {
            List<Long> formIds = customerList.stream().map(RuleCustomerEntity::getFormId).collect(Collectors.toList());
            formIdToPaasNameMap = proFormHelp.getPaasFormList(corpid, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), formIds).stream().collect(Collectors.toMap(PaasFormEntity::getId, PaasFormEntity::getName));
        } catch (Exception e) {
            LOG.error("com.xbongbong.paas.service.impl.CustomerRuleServiceImpl.return2Public：获取表单信息失败：", e);
        }
        for (RuleCustomerEntity customer : customerList) {
            customerIdList.add(customer.getId());
            param = userBack2public(customer, user);
            if ((int) param.get("code") == 1) {
                try {
                    //api回调
//                    //发送评分计算消息
//                    scoreCallBackHelper.sendScoreMessage(corpid,XbbRefTypeEnum.CLUE.getCode(),customer.getId());
                    //日志
                    String opObjectId = customer.getId().toString();

//                    JSONObject json = JsonHelperUtil.getJSONObject(customer.getData());
                    String customerName = customer.getName();
                    String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_CUSTOMER_RULE_BACK), ruleName, userName,
                            customerName);
                    // + customer.getPhoneStr()

                    String paasName = formIdToPaasNameMap.get(customer.getFormId());
                    DynamicDTO dynamicDTO = dynamicDetailsHelper.initDynamicDTO(user.getUserId(), CrmLogMemoConstant.DYNAMIC_USER_BACK_SCRIPT, ProjectLogEnum.CUSTOMER_BACK.getSubType(),
                            DynamicDTO.initMemoHolder(userName, Objects.nonNull(paasName) ? paasName : customerName), null, null, customer.getId());
                    dynamicDTOS.add(dynamicDTO);

                    mongoLogHelp.buildLog(corpid, PaasConstant.SYS_USER_ID, I18nMessageUtil.getMessage(PaasConstant.SYS_OPERATING), OperateModuleTypeEnum.OpenSeaRules, OperateTypeEnum.RETURN_TO_PUBLIC, opObjectId, customerName, memo, null);
                } catch (Exception e) {
                    LOG.error("日志记录失败", e);
                }
            }
        }
        dynamicDetailsHelper.insertDynamic(dynamicDTOS, corpid);

        // 删除已经退回公海池客户的"即将退回公海池"的标签
        tagLinkModel.deleteTagByTagTypeAndRefIdIn(user.getCorpid(), TagTypeEnum.PUBLIC_CUSTOMER_RULE.getCode(), customerIdList);
    }

    private Map<String, Object> userBack2public(RuleCustomerEntity customer, UserEntity user) {
        String userId = user.getUserId();
        String corpid = user.getCorpid();
        Long customerId = customer.getId();
        Map<String, Object> retMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("customerId", customerId);
        param.put("userId", userId);
        param.put("corpid", corpid);
        param.put("del", 0);
        Integer count = customerUserModel.getEntitysCount(param);
        if (Objects.equals(count, 0)) {
            retMap.put("code", UserTeamErrorCodeEnum.API_ERROR_390004.getCode());
            retMap.put("msg", UserTeamErrorCodeEnum.API_ERROR_390004.getMsg());
            return retMap;
        }

        List<Long> customerIdList = new ArrayList<>();
        customerIdList.add(customerId);

        boolean flag;
        try {
            flag = userTeamService.updateCustomerTeam(user, customerIdList, UpdateCustomerTeamScenesEnum.PUBLIC_RULE_SCRIPT,customer.getFormId(), SaasMarkEnum.SAAS.getCode(),XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(),DistributorMarkEnum.OTHER.getCode(),null);
        } catch (XbbException e) {
            LOG.error("updateCustomerTeam error", e);
            flag = false;
        }
        if (flag) {
            retMap.put("code", ErrorCodeEnum.API_SUCCESS.getCode());
            retMap.put("msg", ErrorCodeEnum.API_SUCCESS.getMsg());
        } else {
            retMap.put("code", ErrorCodeEnum.API_FAIL.getCode());
            retMap.put("msg", ErrorCodeEnum.API_FAIL.getMsg());
        }
        return retMap;
    }

    /**
     * 用于移除已退回的客户
     *
     * @param customerList
     * @param backCustomerList
     */
    private void remove(List<RuleCustomerEntity> customerList, List<RuleCustomerEntity> backCustomerList) {
        if (backCustomerList == null || backCustomerList.isEmpty()) {
            return;
        }

        //需要移除的客户id集合
        Set<Long> customerIdSet = new HashSet<>();
        for (RuleCustomerEntity customer : backCustomerList) {
            customerIdSet.add(customer.getId());
        }

        Iterator<RuleCustomerEntity> it = customerList.iterator();
        while (it.hasNext()) {
            RuleCustomerEntity customer = it.next();
            if (customerIdSet.contains(customer.getId())) {
                it.remove();
            }
        }

    }

    /**
     * 是否推送给主负责人
     *
     * @param corpid
     * @return 创建时间 2019/2/27 7:30 PM
     * 修改时间 2019/2/27 7:30 PM
     * @author chy
     * @version v1.0
     * @since v1.0
     */
    private boolean getIsPushMain(String corpid) {
        CustomerPushSet customerPushSet = new CustomerPushSet();
        PushSetEntity pushSetEntity = customerPushSet.getPushSet(corpid, PushTypeEnum.CUSTOMER_BACK_PUBLIC.getSubCode(), pushSetModel);
        boolean isPushMain = false;
        if (Objects.equals(pushSetEntity.getEnable(), 1)) {
            String pushObjectString = pushSetEntity.getPushObject();
            JSONObject pushObject = JsonHelperUtil.parseObject(pushObjectString);
            String typeString = pushObject.getString("type");
            JSONArray typeJsonArray = JsonHelperUtil.parseArray(typeString);
            for (Object object : typeJsonArray) {
                JSONObject jsonObject = (JSONObject) object;
                Integer enable = jsonObject.getInteger("enable");
                if (Objects.equals(enable, 1)) {
                    String alias = jsonObject.getString("alias");
                    if (Objects.equals(alias, PushObjectTypeEnum.MAINUSER.getAlias())) {
                        isPushMain = true;
                    }
                }
            }
        } else {
            isPushMain = false;
        }
        return isPushMain;
    }

    /**
     * 获取脚本相关的公海规则 无新建跟进客户规则  无新建机会客户规则  无新建合同客户规则 最大拥有客户数规则
     *
     * @return 创建时间 2019/2/27 4:51 PM
     * 修改时间 2019/2/27 4:51 PM
     * @author chy
     * @version v1.0
     * @since v1.0
     */
    private List<CustomerRuleEntity> getRuleRelatedScript(String corpid) {
        //获取公司所有的相关公海规则   无新建跟进客户规则  无新建机会客户规则  无新建合同客户规则 最大拥有客户数规则
        List<Integer> ruleTypeIn = new ArrayList<>();
        ruleTypeIn.add(CustomerRuleEnum.NO_CUSTOMER_COMMUNICATE_RULE.getCode());
        ruleTypeIn.add(CustomerRuleEnum.NO_OPPORTUNITY_RULE.getCode());
        ruleTypeIn.add(CustomerRuleEnum.NO_CONTRACT_RULE.getCode());
        ruleTypeIn.add(CustomerRuleEnum.MAX_CUSTOMER_NUM_RULE.getCode());

        //数据库查询，获取影响到获取客户判断的四个规则
        Map<String, Object> param = new HashMap<>(3);
        param.put("corpid", corpid);
        param.put("ruleTypeIn", ruleTypeIn);
        param.put("status", 1);
        param.put("del", 0);
        //最大客户数需要最后执行
        param.put("orderByStr", "rule_type asc");
        return customerRuleModel.findEntitys(param);
    }

    private Integer getRemindTime(String corpid) {
        Integer remindTime = 3;
        try {
            CompanyConfigEntity companyConfig = companyConfigModel.getConfigEntity(corpid,
                    CompanyConfigEnum.PUBLIC_RULE_REMIND_TIME.getAlias());
            if (companyConfig != null) {
                remindTime = StringUtil.toInt(companyConfig.getConfigValue(), 3);
            }
        } catch (Exception e) {
            LOG.error("getRemindTime异常，corpid=" + corpid, e);
        }
        return remindTime;
    }

    /**
     * 【web】公海规则设置选择员工
     *
     * @param customerRuleUserListDTO 公海规则设置选择员工入参
     * @return Integer
     * @throws XbbException 业务异常
     * @version v1.0
     * @since v1.0
     */
    @Override
    public XbbResponse<CustomerRuleUserListVO> userList(CustomerRuleUserListDTO customerRuleUserListDTO) throws XbbException {
        List<UserEntity> userList = getAllUserListLimit500(customerRuleUserListDTO.getCorpid(),
                customerRuleUserListDTO.getUserNameLike(), null);

        CustomerRuleUserListVO userArray = new CustomerRuleUserListVO();
        List<CustomerUserPojo> userPojoList = new ArrayList<>();
        for (UserEntity user : userList) {
            CustomerUserPojo customerUserPojo = new CustomerUserPojo();
            customerUserPojo.setUserId(user.getUserId());
            customerUserPojo.setName(user.getName());
            userPojoList.add(customerUserPojo);
        }
        userArray.setUserArray(userPojoList);
        return new XbbResponse<>(userArray);
    }

    @Override
    @Async(value = "returnPublicCustomerThreadPool")
    public XbbResponse<ReturnCustomer2PublicAsyncVO> returnCustomer2PublicAsync(ReturnCustomer2PublicAsyncDTO returnCustomer2PublicAsyncDTO) throws XbbException {
        String[] split = returnCustomer2PublicAsyncDTO.getLocale().split("_");
        LocaleContextHolder.setLocale(new Locale(split[0], split[1]));
        ReturnCustomer2PublicAsyncVO returnCustomer2PublicVO = new ReturnCustomer2PublicAsyncVO();
        String singleCorpid = returnCustomer2PublicAsyncDTO.getCorpid();

        boolean back = returnCustomer2PublicAsyncDTO.getBack();

        boolean notify = returnCustomer2PublicAsyncDTO.getNotify();

        List<String> corpids = returnCustomer2PublicAsyncDTO.getCorpids();
        //boolean isGrayEnvironmentEnable = sysEnvHelp.isGrayEnvironmentEnable();
        List<CompanyEntity> companyList;
        if (StringUtil.isNotEmpty(singleCorpid)) {
            //灰度判断逻辑去掉
//            if (sysEnvHelp.isGrayEnvironment()) {
//                if (!isGrayEnvironmentEnable) {
//                    return new XbbResponse<>(returnCustomer2PublicVO);
//                }
//                if (!sysEnvHelp.checkIsCrayCompany(singleCorpid)) {
//                    return new XbbResponse<>(returnCustomer2PublicVO);
//                }
//            } else {
//                if (isGrayEnvironmentEnable) {
//                    if (sysEnvHelp.checkIsCrayCompany(singleCorpid)) {
//                        return new XbbResponse<>(returnCustomer2PublicVO);
//                    }
//                }
//            }
            if (commonHelp.isCustomerPublicPoolSeniorModel(singleCorpid)){
                LOG.warn("该公司开启了客户公海高级模式，停止定时任务！");
                return new XbbResponse<>(returnCustomer2PublicVO);
            }
            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("del", 0);
            params.put("corpid", singleCorpid);
            params.put("start", 0);
            params.put("pageNum", 1);
            companyList = companyModel.findEntitys(params);
            if (companyList.size() > 0) {
                backToPublic(singleCorpid, notify, back);
                LOG.info("公司（ID=" + companyList.get(0).getCorpid() + "）：退回公海池任务执行完成！");
                LOG.info("returnCustomer_finished:" + companyList.get(0).getCorpid());
            }
        } else {
            //去除开启了客户公海高级模式的公司
            publicSeniorRuleHelp.removeCorpidsByModel(corpids,false,XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode());

            for (String corpid : corpids) {
                //灰度判断逻辑去掉
//                if (sysEnvHelp.isGrayEnvironment()) {
//                    if (!isGrayEnvironmentEnable) {
//                        continue;
//                    }
//                    if (!sysEnvHelp.checkIsCrayCompany(corpid)) {
//                        continue;
//                    }
//                } else {
//                    if (isGrayEnvironmentEnable) {
//                        if (sysEnvHelp.checkIsCrayCompany(corpid)) {
//                            continue;
//                        }
//                    }
//                }
                backToPublic(corpid, notify, back);
                LOG.info("公司（ID=" + corpid + "）：退回公海池任务执行完成！");
                LOG.info("returnCustomer_finished:" + corpid);
            }
        }
        return new XbbResponse<>(returnCustomer2PublicVO);
    }

    /**
     * 公海池规则处理
     *
     * @param ruleType
     * @param corpid
     * @return
     * @throws XbbException
     */
    private CustomerRuleDetailVO detail(Integer ruleType, String corpid) throws XbbException {
        CustomerRuleDetailVO customerRuleDetailVO = new CustomerRuleDetailVO();
        CustomerRuleEntity rule = customerRuleModel.getByRuleType(ruleType, corpid);
        Integer status = 0;
        if (rule != null) {
            status = rule.getStatus();
        }
        IOperateRuleValue operateRuleValue = OperateRuleValueFactory.operateRuleValueFactory(ruleType);
        Object ruleObject = operateRuleValue.toObject(rule);

        List<String> specialUserList = operateRuleValue.getAllSpecialUser(ruleObject);
        // 规则用户格式封装
        if(ruleObject != null){
            JSONArray userArr = new JSONArray();
            Integer type = null;
            if(!Objects.equals(ruleType, CustomerRuleEnum.PRE_PRINCIPAL_RULE.getCode()) &&
                    !Objects.equals(ruleType, CustomerRuleEnum.GAIN_RATE_RULE.getCode())){
                userArr = ((JSONObject)ruleObject).getJSONArray("restrict");
                type = ((JSONObject) ruleObject).getInteger("type");
                String label = ((JSONObject) ruleObject).getString("label");
                List<Long> labelIds = JSONArray.parseArray(label, Long.class);
                if (CollectionsUtil.isNotEmpty(labelIds)) {
                    Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    param.put("corpid", corpid);
                    param.put("del", DelEnum.NORMAL.getDel());
                    param.put("idIn", labelIds);
                    param.put("columns", "id,lable_name,form_id,lable_color");
                    List<LabelEntity> byLabelIds = labelModel.findEntitys(param);

                    Set<Long> formIds = new HashSet<>();
                    Map<Long, LabelEntity> labelEntityMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    for (LabelEntity entity : byLabelIds) {
                        labelEntityMap.put(entity.getId(), entity);
                        formIds.add(entity.getFormId());
                    }

                    Map<Long, String> formIdAndName = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    if (CollectionsUtil.isNotEmpty(formIds)) {
                        Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        map.put("corpid", corpid);
                        map.put("del", DelEnum.NORMAL.getDel());
                        map.put("idIn", formIds);
                        List<PaasFormEntityExt> entitys = paasFormModel.findEntitys(map);
                        for (PaasFormEntityExt entity : entitys) {
                            formIdAndName.put(entity.getId(), entity.getName());
                        }
                    }
                    List<PublicRuleLabelPojo> ruleLabelPojos = new ArrayList<>();
                    for (Long id : labelIds) {
                        LabelEntity entity = labelEntityMap.get(id);
                        if (Objects.isNull(entity)) {
                            continue;
                        }
                        Long formId = entity.getFormId();
                        String name = entity.getName();
                        if (formIdAndName.containsKey(formId)) {
                            String formName = formIdAndName.get(formId);
                            // 名称一样的，需要在给标签名称改为“表单名称/标签名称”
                            if (StringUtil.isNotEmpty(formName)) {
                                name = formName + "/" + name;
                                entity.setName(name);
                            }
                        }
                        PublicRuleLabelPojo ruleLabelPojo = new PublicRuleLabelPojo();
                        BeanUtil.copyProperties(entity, ruleLabelPojo, true);
                        ruleLabelPojos.add(ruleLabelPojo);
                    }

                    ((JSONObject) ruleObject).put("label", ruleLabelPojos);
                }
            } else {
                userArr = (JSONArray) ruleObject;
            }
            if(!userArr.isEmpty()){
                for(Object userObj : userArr){
                    JSONArray specialUserArr = ((JSONObject)userObj).getJSONArray("users");
                    if(specialUserArr != null){
                        List<String> idList = JSON.parseArray(specialUserArr.toJSONString(), String.class);
                        List<UserEntity> getByUserId = userModel.getByUserId(idList, corpid);
                        List<OptionalRangeEntity> optionalRangeEntityList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        for(UserEntity userEntity : getByUserId){
                            OptionalRangeEntity optionalRangeEntity = new OptionalRangeEntity();
                            optionalRangeEntity.setId(userEntity.getUserId());
                            optionalRangeEntity.setName(userEntity.getName());
                            optionalRangeEntity.setEditable(1);
                            optionalRangeEntity.setProperty(OptionalRangeEnum.USER.getValue());
                            optionalRangeEntityList.add(optionalRangeEntity);
                        }
                        JSONArray deptArr = ((JSONObject)userObj).getJSONArray("depts");
                        if(deptArr != null){
                            // 因为前端回显人员和部门是用同一个组件，所以这里部门也加在人员一起
                            List<Long> deptIds = JSON.parseArray(deptArr.toJSONString(), Long.class);
                            List<DepartmentEntity> deptEntitys = departmentModel.getByDepIdIn(corpid, deptIds);
                            for(DepartmentEntity departmentEntity : deptEntitys){
                                OptionalRangeEntity optionalRangeEntity = new OptionalRangeEntity();
                                optionalRangeEntity.setId(departmentEntity.getId().toString());
                                optionalRangeEntity.setName(departmentEntity.getName());
                                optionalRangeEntity.setEditable(1);
                                optionalRangeEntity.setProperty(OptionalRangeEnum.DEPT.getValue());
                                optionalRangeEntityList.add(optionalRangeEntity);
                            }
                        }
                        JSONArray roleArr = ((JSONObject)userObj).getJSONArray("roles");
                        if(roleArr != null){
                            // 因为前端回显人员和部门是用同一个组件，所以这里部门也加在人员一起
                            List<Integer> roleIds = JSON.parseArray(roleArr.toJSONString(), Integer.class);
                            List<RoleEntity> roleEntities = roleModel.getByRoleIdIn(corpid, roleIds);
                            for(RoleEntity roleEntity : roleEntities){
                                OptionalRangeEntity optionalRangeEntity = new OptionalRangeEntity();
                                optionalRangeEntity.setId(roleEntity.getId().toString());
                                optionalRangeEntity.setName(roleEntity.getRoleName());
                                optionalRangeEntity.setEditable(1);
                                optionalRangeEntity.setProperty(OptionalRangeEnum.ROLE.getValue());
                                optionalRangeEntityList.add(optionalRangeEntity);
                            }
                        }
                        ((JSONObject) userObj).put("users", optionalRangeEntityList);
                    }
                    if (Objects.equals(type, ChildCustomerRuleEnum.CUSTOMER_LABEL.getCode())) {
                        JSONArray array = ((JSONObject)userObj).getJSONArray("array");
                        for (Object obj : array) {
                            String key;
                            try {
                                key = ((JSONObject)obj).getString("key");
                            } catch (Exception e) {
                                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100015);
                            }
                            List<Long> labelIds = JSONArray.parseArray(key, Long.class);
                            if (CollectionsUtil.isNotEmpty(labelIds)) {
                                Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                                param.put("corpid", corpid);
                                param.put("del", DelEnum.NORMAL.getDel());
                                param.put("idIn", labelIds);
                                param.put("columns", "id,lable_name,form_id,lable_color");
                                List<LabelEntity> byLabelIds = labelModel.findEntitys(param);

                                Set<Long> formIds = new HashSet<>();
                                Map<Long, LabelEntity> labelEntityMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                                for (LabelEntity entity : byLabelIds) {
                                    labelEntityMap.put(entity.getId(), entity);
                                    formIds.add(entity.getFormId());
                                }

                                Map<Long, String> formIdAndName = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                                if (CollectionsUtil.isNotEmpty(formIds)) {
                                    Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                                    map.put("corpid", corpid);
                                    map.put("del", DelEnum.NORMAL.getDel());
                                    map.put("idIn", formIds);
                                    List<PaasFormEntityExt> entitys = paasFormModel.findEntitys(map);
                                    for (PaasFormEntityExt entity : entitys) {
                                        formIdAndName.put(entity.getId(), entity.getName());
                                    }
                                }
                                JSONArray jsonArray = new JSONArray();
                                for (Long id : labelIds) {
                                    LabelEntity entity = labelEntityMap.get(id);
                                    if (Objects.isNull(entity)) {
                                        continue;
                                    }
                                    Long formId = entity.getFormId();
                                    String name = entity.getName();
                                    if (formIdAndName.containsKey(formId)) {
                                        String formName = formIdAndName.get(formId);
                                        // 名称一样的，需要在给标签名称改为“表单名称/标签名称”
                                        if (StringUtil.isNotEmpty(formName)) {
                                            name = formName + "/" + name;
                                            entity.setName(name);
                                        }
                                    }
                                    JSONObject jsonObject = new JSONObject();
                                    jsonObject.put("id", id);
                                    jsonObject.put("name", name);
                                    jsonObject.put("formId", formId);
                                    jsonObject.put("color", entity.getColor());
                                    jsonArray.add(jsonObject);
                                }{

                                }
                                ((JSONObject)obj).put("key", jsonArray.toJSONString());
                            }
                        }
                    }
                }
            }

            customerRuleDetailVO.setRuleValue(ruleObject);
        }else {
            //新公司初始化 ruleValue为null
            Object ruleValue = publicSeniorRuleHelp.initPublicRule(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(),ruleType,false);
            customerRuleDetailVO.setRuleValue(ruleValue);
        }
        customerRuleDetailVO.setStatus(status);
        return customerRuleDetailVO;
    }

    /**
     * 公海规则设置选择员工
     *
     * @param corpid       公司id
     * @param userNameLike 员工姓名模糊查询
     * @version v1.0
     * @since v1.0
     */
    public List<UserEntity> getAllUserListLimit500(String corpid, String userNameLike, List<String> userIdIn) {
        if (userIdIn != null && userIdIn.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, Object> param = new HashMap<String, Object>(16);
        param.put("columns", "id,department,avatar,user_id,name,role_ids,is_boss");
        param.put("corpid", corpid);
        param.put("del", DelEnum.NORMAL.getDel());
        param.put("nameLike", userNameLike);
        param.put("userIdIn", userIdIn);

        // 当不指定员工时才分页，否则当userIdIn.size()大于分页数时，会有部分数据搜不到
        if (userIdIn == null) {
            param.put("start", 0);
            // 最多查询100个
            param.put("pageNum", 100);
        }
        List<UserEntity> userList = userModel.findEntitys(param);
        return userList;
    }

    /**
     * 客户星级数据封装
     *
     * @param isSort
     * @return
     */
    private List<CustomerRulePojo> getImportantDegree(boolean isSort) {
        List<CustomerRulePojo> rulePojoList = new ArrayList<>();
        for (StarEnum type : StarEnum.values()) {
            if (type == StarEnum.UNKNOW || type == StarEnum.ZERO) {
                continue;
            }
            CustomerRulePojo rulePojo = new CustomerRulePojo();
            rulePojo.setKey(String.valueOf(type.getValue()));
            if (StarEnum.ONE.getValue() == type.getValue()) {
                if (isSort) {
                    rulePojo.setValue(StarEnum.getStarByValue(type.getValue()).getText());
                } else {
                    rulePojo.setValue(I18nMessageUtil.getMessage(CustomerRuleConstant.ONE_AND_MORE_STAR));
                }
            } else {
                rulePojo.setValue(type.getText());
            }
            rulePojoList.add(rulePojo);
        }
        return rulePojoList;
    }

    /**
     * @param ruleType 规则类型
     * @return
     * @Description: 获取规则的子类型选项
     * @author youli.chen
     * @version v1.0
     * @since v1.0
     */
    private List<CustomerRuleTypePojo> getChildTypeList(Integer ruleType) {
        List<CustomerRuleTypePojo> rulePojoList = new ArrayList<>();
        if (ruleType == null) {
            return new ArrayList<>();
        }
        CustomerRuleEnum customerRule = CustomerRuleEnum.getByCode(ruleType);
        switch (customerRule) {
            case NO_CUSTOMER_COMMUNICATE_RULE:
            case NO_OPPORTUNITY_RULE:
            case NO_CONTRACT_RULE:
                rulePojoList = getChildTypeList(false);
                break;
            case MAX_CUSTOMER_NUM_RULE:
                rulePojoList = getChildTypeList(true);
                break;
            default:
                break;
        }
        return rulePojoList;
    }

    /**
     * 规则的子类型选项
     *
     * @author youli.chen
     * @date 2019/1/22 16:47
     * @since v1.0
     */
    public static List<CustomerRuleTypePojo> getChildTypeList(boolean numRule) {
        List<CustomerRuleTypePojo> typeList = new ArrayList<>();
        for (CustomerChildTypeEnum type : CustomerChildTypeEnum.values()) {
            if (type == CustomerChildTypeEnum.UNKNOWN) {
                continue;
            }

            //是最大客户数规则没有根据客户状态设置
            if (numRule && type == CustomerChildTypeEnum.CUSTOMER_CHILD_ONE_STAR) {
                continue;
            }

            CustomerRuleTypePojo customerRuleTypePojo = new CustomerRuleTypePojo();
            customerRuleTypePojo.setKey(type.getCode());
            customerRuleTypePojo.setValue(type.getName());
            typeList.add(customerRuleTypePojo);
        }
        return typeList;
    }

    /**
     * 公海池规则数据封装插入或更新
     *
     * @param corpid              公司id
     * @param customerRuleSaveDTO
     * @return
     * @throws XbbException
     */
    private Integer save(String corpid, CustomerRuleSaveDTO customerRuleSaveDTO) throws XbbException {

        IOperateRuleValue operateRuleValue = OperateRuleValueFactory.operateRuleValueFactory(customerRuleSaveDTO.getRuleType());
        String ruleValue = null;
        // 1.拜访时间2.有无机会3.有无合同4.总数限制
        RuleSavePojo ruleSavePojo = customerRuleSaveDTO.getRuleValue();
        if (ruleSavePojo != null) {
            String getRuleValue;
            try {
                getRuleValue = JSON.toJSONString(ruleSavePojo);
            } catch (Exception e) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100015);
            }
            operateRuleValue.verify(getRuleValue);
            // 特殊处理
            if(getRuleValue != null){
                JSONObject ruleValueObject = JSONArray.parseObject(getRuleValue);
                List<RestrictPojo> restrictList = ruleSavePojo.getRestrict();
                if(!restrictList.isEmpty()){
                    JSONArray userArr = JSONArray.parseArray(JSON.toJSONString(restrictList));
                    if(!userArr.isEmpty()){
                        for(Object userObj : userArr){
                            JSONArray specialUserArr = ((JSONObject)userObj).getJSONArray("users");
                            if(specialUserArr != null){
                                List<String> users = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                                List<String> depts = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                                List<String> roles = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                                specialUserArr.forEach(item -> {
                                    String property = ((JSONObject) item).getString("property");
                                    String id = ((JSONObject) item).getString("id");
                                    if (Objects.equals(property, OptionalRangeEnum.USER.getValue())) {
                                        users.add(id);
                                    } else if (Objects.equals(property, OptionalRangeEnum.DEPT.getValue())) {
                                        depts.add(id);
                                    } else if (Objects.equals(property, OptionalRangeEnum.ROLE.getValue())) {
                                        roles.add(id);
                                    }
                                });
                                ((JSONObject) userObj).put("users", users);
                                if (!depts.isEmpty()) {
                                    // 因为上面的人员是直接存数组的，所以部门这里为了区分只能是另放在depts里面
                                    ((JSONObject) userObj).put("depts", depts);
                                }
                                if (!roles.isEmpty()) {
                                    // 因为上面的人员是直接存数组的，所以角色这里为了区分只能是另放在roles里面
                                    ((JSONObject) userObj).put("roles", roles);
                                }
                            }
                        }
                    }
                    JSONArray restrictJsonArray = ruleValueObject.getJSONArray("restrict");
                    if(restrictJsonArray != null){
                        for(Object restrictObj : restrictJsonArray){
                            JSONArray array = ((JSONObject)restrictObj).getJSONArray("users");
                            if(array != null){
                                ruleValueObject.put("restrict", userArr);
                            }
                        }
                    }
                }
                getRuleValue = ruleValueObject.toJSONString();
            }
            ruleValue = getRuleValue;
        }
        // 5.前负责人规则6.捞取频次限制
        List<LeadOrFrePojo> leadOrFre = customerRuleSaveDTO.getLeadOrFre();
        if (leadOrFre != null) {
            String getLeadOrFre;
            try {
                getLeadOrFre = JSONArray.toJSONString(leadOrFre);
            } catch (Exception e) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100015);
            }
            operateRuleValue.verify(getLeadOrFre);

            if(getLeadOrFre != null){
                JSONArray userArr = JSONArray.parseArray(getLeadOrFre);
                if(!userArr.isEmpty()){
                    for(Object userObj : userArr){
                        JSONArray specialUserArr = ((JSONObject)userObj).getJSONArray("users");
                        if(specialUserArr != null){
                            List<String> users = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                            List<String> depts = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                            List<String> roles = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                            specialUserArr.forEach(item -> {
                                String property = ((JSONObject) item).getString("property");
                                String id = ((JSONObject) item).getString("id");
                                if (Objects.equals(property, OptionalRangeEnum.USER.getValue())) {
                                    users.add(id);
                                } else if (Objects.equals(property, OptionalRangeEnum.DEPT.getValue())) {
                                    depts.add(id);
                                } else if (Objects.equals(property, OptionalRangeEnum.ROLE.getValue())) {
                                    roles.add(id);
                                }
                            });
                            ((JSONObject) userObj).put("users", users);
                            if (!depts.isEmpty()) {
                                // 因为上面的人员是直接存数组的，所以部门这里为了区分只能是另放在depts里面
                                ((JSONObject) userObj).put("depts", depts);
                            }
                            if (!roles.isEmpty()) {
                                // 因为上面的人员是直接存数组的，所以角色这里为了区分只能是另放在roles里面
                                ((JSONObject) userObj).put("roles", roles);
                            }
                        }
                    }
                }
                getLeadOrFre = userArr.toJSONString();
            }

            ruleValue = getLeadOrFre;
        }

        Integer ruleType = customerRuleSaveDTO.getRuleType();
        Integer status = customerRuleSaveDTO.getStatus();

        CustomerRuleEntity ruleEntity = customerRuleModel.getByRuleType(ruleType, corpid);

        if (ruleEntity == null) {
            ruleEntity = new CustomerRuleEntity();
            ruleEntity.setCorpid(corpid);
            ruleEntity.setRuleType(ruleType);
        }
        ruleEntity.setStatus(status);
        ruleEntity.setRuleValue(ruleValue);

        Integer saveId;
        try {
            saveId = customerRuleModel.save(ruleEntity);
        } catch (Exception e) {
            LOG.error("公海池规则数据插入或更新失败，corpid=" + corpid, e);
            throw new XbbException(PublicPoolErrorCodeEnum.API_ERROR_218004);
        }
        return saveId;
    }

    /**
     * 公海池规则保存时的日志保存
     *
     * @param corpid    公司ID
     * @param oldEntity
     * @param newEntity
     * @throws XbbException
     */
    private void saveLog(String corpid, CustomerRuleEntity oldEntity, CustomerRuleEntity newEntity,
                         CustomerRuleSaveDTO customerRuleSaveDTO) throws XbbException {
        if (newEntity == null) {
            LOG.error("新公海规则为空");
            throw new XbbException(PublicPoolErrorCodeEnum.API_ERROR_218005);
        }
        // 数据字典项：获取客户状态
        Map<String, String> customerStatusMap = dataDictionaryModel.getDictionaryMap(DictionaryEnum.CUSTOMER_STATUS, corpid, null);

        // 公海池规则
        Integer ruleType = newEntity.getRuleType();

        IOperateRuleValue operateRuleValue = OperateRuleValueFactory.operateRuleValueFactory(ruleType);
        Integer oldStatus = operateRuleValue.getStatus(oldEntity);
        Integer oldContract = operateRuleValue.getContract(oldEntity);
        Integer oldOpportunity = operateRuleValue.getOpportunity(oldEntity);
        JSONArray oldCustomerStatusArray = operateRuleValue.getCustomerStatus(oldEntity);
        Integer oldType = operateRuleValue.getType(oldEntity);
        JSONArray oldRestrict = operateRuleValue.getRestrict(oldEntity);
        List<Long> oldLabelIds = null;
        if ( Objects.nonNull(oldEntity) ) {
            oldLabelIds = operateRuleValue.getCustomerLabelIds(oldEntity.getRuleValue());
        }

        Integer newStatus = operateRuleValue.getStatus(newEntity);
        Integer newContract = operateRuleValue.getContract(newEntity);
        Integer newOpportunity = operateRuleValue.getOpportunity(newEntity);
        JSONArray newCustomerStatusArray = operateRuleValue.getCustomerStatus(newEntity);
        Integer newType = operateRuleValue.getType(newEntity);
        JSONArray newRestrict = operateRuleValue.getRestrict(newEntity);
        List<Long> newLabelIds = operateRuleValue.getCustomerLabelIds(newEntity.getRuleValue());

        JSONObject oldBackRule = null;
        JSONObject newBackRule = null;
        if (Objects.equals(ruleType, CustomerRuleEnum.MAX_CUSTOMER_NUM_RULE.getCode())) {
            oldBackRule = ((OperateMaxCustomerNumRuleValue) operateRuleValue).getBackRule(oldEntity);
            newBackRule = ((OperateMaxCustomerNumRuleValue) operateRuleValue).getBackRule(newEntity);
        }

        // 日志备注拼接
        memo(corpid, newEntity, oldStatus, oldContract, oldOpportunity, oldCustomerStatusArray, oldType, oldRestrict,oldLabelIds,
                newStatus, newContract, newOpportunity, newCustomerStatusArray, newType, newRestrict, newLabelIds, oldBackRule,
                newBackRule, ruleType, customerStatusMap, customerRuleSaveDTO);
    }

    /**
     * 日志备注字段的拼接
     *
     * @param corpid                 公司ID
     * @param newEntity              客户公海池规则实体
     * @param oldStatus              老状态
     * @param oldContract            老合同
     * @param oldOpportunity         老销售机会
     * @param oldCustomerStatusArray 老客户状态list
     * @param oldType                老类型
     * @param oldRestrict            老限制条件
     * @param newStatus              新状态
     * @param newContract            新合同
     * @param newOpportunity         新销售机会
     * @param newCustomerStatusArray 新客户状态list
     * @param newType                新类型
     * @param newRestrict            新限制条件
     * @param oldBackRule            老退回规则
     * @param newBackRule            新退回规则
     * @param ruleType               1.跟进时间 2.有无机会 3.有无合同 4.总数限制
     * @param customerStatusMap      数据字典
     * @param customerRuleSaveDTO    公海池保存规则入参
     * @return 日志备注字段的拼接字符串
     */
    private void memo(String corpid, CustomerRuleEntity newEntity, Integer oldStatus, Integer oldContract, Integer oldOpportunity,
                      JSONArray oldCustomerStatusArray, Integer oldType, JSONArray oldRestrict, List<Long> oldLabelIds, Integer newStatus, Integer newContract,
                      Integer newOpportunity, JSONArray newCustomerStatusArray, Integer newType, JSONArray newRestrict, List<Long> newLabelIds, JSONObject oldBackRule,
                      JSONObject newBackRule, Integer ruleType, Map<String, String> customerStatusMap, CustomerRuleSaveDTO customerRuleSaveDTO) throws XbbException {
        String userId = customerRuleSaveDTO.getUserId();
        // 登录用户
        String loginUserName = customerRuleSaveDTO.getLoginUserName();
        // 公海池规则名称
        String opObjectName = CustomerRuleEnum.getByCode(ruleType).getName();
        String defaultMemo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_CUSTOMER_RULE), loginUserName, opObjectName);

        OperateTypeEnum operateTypeEnum = OperateTypeEnum.EDIT;
        // 是否启用或关闭某种规则
        String isOpenRule = null;
        if (!Objects.equals(newStatus, oldStatus)) {
            if (Objects.equals(newStatus, 0)) {
                operateTypeEnum = OperateTypeEnum.CLOSE;
                // 操作类型标识
                isOpenRule = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_CLOSE_CUSTOMER_RULE), opObjectName);
            } else {
                operateTypeEnum = OperateTypeEnum.ENABLE;
                // 操作类型标识
                isOpenRule = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_OPEN_CUSTOMER_RULE), opObjectName);
            }
        }
        // 标签变化
        String changLabel = null;
        if(CollectionUtils.isNotEmpty(oldLabelIds) || CollectionUtils.isNotEmpty(newLabelIds)) {
            List<String> labelListOld = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<String> labelIdListNew = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            String oldStr = "";
            String newStr = "";
            if(oldLabelIds.size() > 0){
                List<LabelEntity> labelEntityList = labelModel.getByLabelIds(oldLabelIds, corpid);
                labelEntityList.forEach(labelEntity -> labelListOld.add(labelEntity.getName()));
                oldStr = StringUtils.join(labelListOld, "，");
            }
            if(newLabelIds.size() > 0){
                List<LabelEntity> labelEntityList = labelModel.getByLabelIds(newLabelIds, corpid);
                labelEntityList.forEach(labelEntity -> labelIdListNew.add(labelEntity.getName()));
                newStr = StringUtils.join(labelIdListNew, "，");
            }
            if(oldStr != "" || newStr != ""){
                changLabel = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_LABEL_RULE), oldStr, newStr);
            }
        }
        // 是否取消设置公海池规则不包含有合同的客户
        String setTingContractRule = null;
        if (!Objects.equals(newContract, oldContract)) {
            if (Objects.equals(newContract, 0)) {
                setTingContractRule = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_CANCEL_SETTING_CONTRACT_RULE), opObjectName);
            } else {
                setTingContractRule = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_SETTING_CONTRACT_RULE), opObjectName);
            }
        }
        // 是否取消设置公海池规则不包含有销售机会的客户。
        String setTingOpportunityRule = null;
        if (!Objects.equals(newOpportunity, oldOpportunity)) {
            if (Objects.equals(newOpportunity, 0)) {
                setTingOpportunityRule = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_CANCEL_SETTING_OPPORTUNITY_RULE), opObjectName);
            } else {
                setTingOpportunityRule = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_SETTING_OPPORTUNITY_RULE), opObjectName);
            }
        }
        // 设置是不包含的客户状态
        String notStatusRule = null;
        if (!Objects.equals(newCustomerStatusArray, oldCustomerStatusArray)) {
            if (newCustomerStatusArray.size() == 0) {
                notStatusRule = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_NOT_CUSTOMER_STATUS_RULE), opObjectName);
            } else {
                StringBuilder statusStr = new StringBuilder();
                for (Object statusObject : newCustomerStatusArray) {
                    String statusInt = (String) statusObject;
                    statusStr.append(" " + customerStatusMap.get(statusInt));
                }
                notStatusRule = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_CUSTOMER_STATUS_RULE), opObjectName, statusStr.toString());
            }
        }
        // 编辑设置
        String updateRule = null;
        if (!Objects.equals(newType, oldType)) {
            CustomerChildTypeEnum childCustomerRule = CustomerChildTypeEnum.getChildTypeByCode(newType);
            if (childCustomerRule != CustomerChildTypeEnum.UNKNOWN) {
                updateRule = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_NEW_CUSTOMER_RULE), childCustomerRule.getName());
            }
        }
        // 编辑了数值设置
        String setRule = null;
        if (!Objects.equals(newRestrict, oldRestrict)) {
            setRule = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_DATE_SET));
        }
        // 编辑了超过最大客户数退回规则
        String maxBackRule = null;
        if (!Objects.equals(newBackRule, oldBackRule)) {
            maxBackRule = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_MAX_CUSTOMER_BACK_RULE));
        }
        StringBuilder memoStr = new StringBuilder();
        memoStr.append(defaultMemo);
        if(isOpenRule != null){
            memoStr.append(isOpenRule);
        }
        if(setTingContractRule != null){
            memoStr.append(setTingContractRule);
        }
        if(setTingOpportunityRule != null){
            memoStr.append(setTingOpportunityRule);
        }
        if(notStatusRule != null){
            memoStr.append(notStatusRule);
        }
        if(updateRule != null){
            memoStr.append(updateRule);
        }
        if(setRule != null){
            memoStr.append(setRule);
        }
        if(maxBackRule != null){
            memoStr.append(maxBackRule);
        }
        if(changLabel != null){
            memoStr.append(changLabel);
        }

        mongoLogHelp.buildLog(corpid, userId, loginUserName, OperateModuleTypeEnum.OpenSeaRules, operateTypeEnum,
                newEntity.getId().toString(), OperateModuleTypeEnum.OpenSeaRules.getName(), memoStr.toString(), customerRuleSaveDTO.getHttpHeader());
    }

    /**
     * 公司配置保存公海池退回时间
     *
     * @param corpid 公司ID
     * @param day
     * @throws XbbException
     */
    private Integer saveRemindTime(String corpid, Integer day) throws XbbException {
        String configValue = String.valueOf(day);
        CompanyConfigEntity companyConfig = companyConfigModel.initConfigEntity(corpid,
                CompanyConfigEnum.PUBLIC_RULE_REMIND_TIME.getAlias());

        companyConfig.setConfigValue(configValue);
        companyConfig.setUpdateTime((long) DateUtil.getInt());
        Integer id;
        try {
            id = companyConfigModel.update(companyConfig);
        } catch (Exception e) {
            LOG.error("公司配置保存公海池退回时间失败，corpid=" + corpid, e);
            throw new XbbException(PublicPoolErrorCodeEnum.API_ERROR_218006);
        }
        return id;
    }


    @Override
    public void customerTypeChage(String corpid) throws XbbException {
        List<ItemPoJo> typeItemPoJos = dataDictionaryModel.getDictionaryList4Saas(DictionaryEnum.CUSTOMER_STATUS, corpid, null);

        List<Integer> ruleTypeIn =  new ArrayList<>();
        ruleTypeIn.add(CustomerRuleEnum.NO_CUSTOMER_COMMUNICATE_RULE.getCode());
        ruleTypeIn.add(CustomerRuleEnum.NO_OPPORTUNITY_RULE.getCode());
        ruleTypeIn.add(CustomerRuleEnum.NO_CONTRACT_RULE.getCode());
        ruleTypeIn.add(CustomerRuleEnum.MAX_CUSTOMER_NUM_RULE.getCode());

        //数据库查询，获取影响到获取客户判断的三个规则
        Map<String, Object> param = new HashMap<>(3);
        param.put("corpid", corpid);
        param.put("ruleTypeIn", ruleTypeIn);
        param.put("del", 0);
        List<CustomerRuleEntity> ruleList = customerRuleModel.findEntitys(param);

        for(CustomerRuleEntity rule : ruleList) {
            ICheckRule checkRule = checkRuleFactory.checkRuleFactory(rule.getRuleType());
            JSONObject ruleValueObject = checkRule.customerTypeChage(rule, typeItemPoJos);
            if(ruleValueObject != null){
                rule.setRuleValue(ruleValueObject.toJSONString());
                customerRuleModel.save(rule);
            }
        }

    }

    /**
     * 某人主负责的客户数
     * @param corpid
     * @param userId
     * @return
     * @throws XbbException
     */
    public Integer mainCount(String corpid, String userId) throws XbbException {
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termQuery("del", DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termQuery(CustomerTeamEnum.getEsAttr(CustomerTeamEnum.USER_ID), userId));
        IndexTypeEnum customerTeamIndex = indexTypeModel.getCustomerTeamIndex(corpid, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());

        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, customerTeamIndex.getType()));
        sourceBuilder.query(boolQueryBuilder);
        SearchRequest searchRequest = new SearchRequest(customerTeamIndex.getIndex());
        searchRequest.source(sourceBuilder);
        CountRequest countRequest = new CountRequest(searchRequest.indices()[0]);
        countRequest.query(searchRequest.source().query());
        Long count = xbbElasticsearchRestTemplate.count(countRequest);
        return count.intValue();
    }
}
